#ifndef THEATER_H
#define THEATER_H
#include "synch.h"

#define DEBUG 1

#define DEBUG_OFF        0
#define DEBUG_ERROR      1
#define DEBUG_WARN       2
#define DEBUG_TRACE      3
#define DEBUG_INFO       4
#define DEBUG_LOUD       5
#if DEBUG > 0
#define DBG_STRING      ("*unicorn theater*:  ")
#define DBGPRINT(Level, fmt, args...)         \           
{                                                        \
    if (Level <= DEBUG_INFO)                   \        
    {                                                  \  
        printf(DBG_STRING);                \       
        printf("%s line %u  function %s: ",__FILE__,__LINE__ ,__FUNCTION__);        \  
        printf( fmt, ## args);        \         
    }                                             \       
};

#define DBGPRINT_ERR(fmt, args...)   \
{                                    \
    printf("ERROR!!! ");		 \	
    printf( fmt, ## args); \
};
#else
#define DBGPRINT(Level, fmt, args...)    
#define DBGPRINT_ERR(fmt, args...) 
#endif


#define TICKETCLERKSIZE 5
#define CONCESSIONCLERK_SIZE  5
#define TICKETTAKER_SIZE 3


#define TICKET_PRICE 12
#define POPCORN_PRICE 5
#define SODA_PRICE 4
#define SEATS_SIZE 25

#define OFF_WORK 1
#define ON_WORK 0

#define READY 1
#define NO_READY 0

#define MAX_CUSTOMERS 100000


#define MOVIE_READY 0 //used for the tickettaker to know whether take the ticket or not
#define MOVIE_PLAYING 1 //now playing the movie
#define MOVIE_OVER 2 //now playing the movie


#define READYTOTAKETIC 1
#define NOTREADYTOTAKETIC 0


#define ROOMFULL 1
#define ROOMNOTFULL 0

#define ROOM_NUM 1 //right now we have only one room, so set it to 1

#define SEATS_GOT 1
#define SEATS_FAILED 0
#define SEATSTAKER_BREAK 2

#define ADD_NEWLINE 1
#define NONEWLINE 0

struct CustomerData {
	int customerNumber;
	int groupNumber;
	int groupSize; //Only head customers need this value
};

//varibles used to record
extern unsigned int ticketclrk_totalticksnum[TICKETCLERKSIZE];

extern unsigned int popcorn_totalnum[CONCESSIONCLERK_SIZE];
extern unsigned int soda_totalnum[CONCESSIONCLERK_SIZE];
extern unsigned int food_totalmoney[CONCESSIONCLERK_SIZE];
extern unsigned int all_foodmoney;
extern unsigned int all_ticketmoney;

extern Lock * customerLock[MAX_CUSTOMERS];
extern unsigned int customer_popcorn[MAX_CUSTOMERS];
extern unsigned int customer_soda[MAX_CUSTOMERS];
extern unsigned int customer_seatno[MAX_CUSTOMERS];
extern unsigned int customer_needbath[MAX_CUSTOMERS];
extern Condition * customer_cv[MAX_CUSTOMERS];
extern Semaphore * customer_sem[MAX_CUSTOMERS];

extern Lock * customer_foodLock[MAX_CUSTOMERS];
extern Lock * customer_seatLock[MAX_CUSTOMERS];

extern unsigned int totalCustomer;
extern unsigned int totalCustomerEntered;
extern Lock * totalCustomerLock;
extern Lock * totalCustomerEnteredLock;


//lock for the communications
extern Lock *ticketClerkLineLock; //used for the clerk and the customer to operate the line
extern Lock *ticketClerkMsgLock[TICKETCLERKSIZE]; //used for the clerk and the customer to operate the shared 
                                                                            //variables as tickets_num and so on.
//condition values for the ticketclerk and the customer to communicate                                                                          
extern Condition  *ticketclerkline_cv[TICKETCLERKSIZE]; //used for the clerk to know     
extern Condition  *ticketclerkMsg_cv[TICKETCLERKSIZE]; //used for the clerk and customer to transfer msg   

//customer lines for the ticketclerk
extern unsigned int ticketclrk_cus_count[TICKETCLERKSIZE];

//ticketclerk's state to show whether the ticket clerk is busy or nor
extern unsigned int ticketclrk_state[TICKETCLERKSIZE];
extern unsigned int ticketclrk_off[TICKETCLERKSIZE];//used for the manager to break the ticketclerk off or not
                                                                            // 1 means the clerk could off work and break, 0 means keep on work


//these varibles defined to commnunicate between the customers and ticketclerk.
//for example, the ticketclerks ask the customer how many tickets wants to buy, and the 
//customer could set the global varibles like 4 tickets so the clerk could know how many,
//and continue the communication

//varibles used for customer and ticketclerk
extern unsigned int tickets_num[TICKETCLERKSIZE];     //ticket number the customer want to buy
extern unsigned int tickets_money[TICKETCLERKSIZE];  //ticket money the customer should pay


//for the concession clerk and the customer
//lock for the communication 
extern Lock *concessClerkLineLock; //used for the clerk and the customer to operate the line
extern Lock *concessClerkMsgLock[CONCESSIONCLERK_SIZE]; //used for the clerk and the customer to operate the shared 
                                                                            //variables as tickets_num and so on.
//condition values for the ticketclerk and the customer to communicate                                                                          
extern Condition  *concessclerkline_cv[CONCESSIONCLERK_SIZE]; //used for the clerk to know     
extern Condition  *concessclerkMsg_cv[CONCESSIONCLERK_SIZE]; //used for the clerk and customer to transfer msg   

//customer lines for the ticketclerk
extern unsigned int concessclrk_cus_count[CONCESSIONCLERK_SIZE];

//ticketclerk's state to show whether the ticket clerk is busy or nor
extern unsigned int concessclrk_state[CONCESSIONCLERK_SIZE];
extern unsigned int concessclrk_off[CONCESSIONCLERK_SIZE];//used for the manager to break the concerssion off or not
                                                                            // 1 means the clerk could off work and break, 0 means keep on work

//varibles usef for customer and concession clerk 
extern unsigned int popcorn_num[CONCESSIONCLERK_SIZE];
extern unsigned int soda_num[CONCESSIONCLERK_SIZE];
extern unsigned int food_money[CONCESSIONCLERK_SIZE];

//defined for the ticket taker 
//for the tiket taker and the customer
//lock for the communication 
extern Lock  *seatsRsvLock; //used to count how many customers have entered the room
extern Lock *ticketTakerLineLock; //used for the clerk and the customer to operate the line
extern Lock *ticketTakerMsgLock[TICKETTAKER_SIZE]; //used for the clerk and the customer to operate the shared 
                                                                            //variables as concesss_num and so on.
//condition values for the ticketTaker and the customer to communicate      
extern Condition  *ticketTakerline_cv[TICKETTAKER_SIZE]; //used for the clerk to know     
extern Condition  *ticketTakerMsg_cv[TICKETTAKER_SIZE]; //used for the clerk and customer to transfer msg   

//customer lines for the ticketTaker
extern unsigned int ticketTaker_cus_count[TICKETTAKER_SIZE];

//ticketTaker's state t o show whether the concess clerk is busy or nor
extern unsigned int ticketTaker_state[TICKETTAKER_SIZE];
extern unsigned int ticTkr_ready;//changed by the manager to know whether it is time to take the ticket

extern unsigned int seats_from[TICKETTAKER_SIZE];  //ticket money the customer should pay
extern unsigned int seats_to[TICKETTAKER_SIZE];  //ticket money the customer should pay
extern unsigned int seats_result[TICKETTAKER_SIZE];

//global varables for ticket taker and the customers
extern unsigned int tictaker_tic_number[TICKETTAKER_SIZE];
extern unsigned int seatsReserved;
extern unsigned int room_number[TICKETTAKER_SIZE];

//used for the movie technician


extern unsigned int movie_state;
extern Lock  *movie_stateLock; 
extern Condition  *movieState_cv;


//used to check the room is full or not, if the room is full, the movie technician could start the movie
extern unsigned int RoomFull;
extern Lock  *roomfullLock; 
//extern Condition  *roomfull_cv;

extern Lock *ticTkrReadyLock[TICKETTAKER_SIZE]; 
extern Condition *ticTkrReady_cv[TICKETTAKER_SIZE]; 

extern Lock  *movieReadyLock; 
extern Condition  *movieReady_cv;

extern Lock * movieTechMsgLock;
extern Condition * movieTechMsg_cv;


extern unsigned int ticketTaker_off[TICKETTAKER_SIZE];//used for the manager to break the concerssion off or not

extern unsigned int ticketclrk_addNewline[TICKETCLERKSIZE];
extern unsigned int foodclrk_addNewline[CONCESSIONCLERK_SIZE];
extern unsigned int tickettaker_addNewline[TICKETTAKER_SIZE];


extern unsigned int numGroups;
extern unsigned int numCustomers;
extern unsigned int numTicketClerks;
extern unsigned int numConcessionClerks;
extern unsigned int numTicketTakers;
extern unsigned int numGroupsRemaining;

extern unsigned int totalCustomerLeft;
extern Lock * totalCustomerLeftLock;

void ticketClerk_startWork(unsigned int ticketclerk_workno);
void concessionClerk_startWork(unsigned int ticketclerk_workno);
void ticketTaker_startWork(unsigned int tictaker_workno);
void movieTechnician_startWork(unsigned int movTech_workno);
void headCustomer_start(int cus);
void generatCustomer();
void divideIntoGroups();
void Manager_startWork(unsigned int manager_workno);
void regularCustomer_startWork(int cus);
void sendMoneyToManagerFromTicketClerk(int clerkNumber, int moneyAmount);
void sendMoneyToManagerFromConcessionClerk(int clerkNumber, int moneyAmount);



#endif //THEATER_H

